

import os
import json
import pygame as pg
from .. import tool
from .. import constants as c
from ..component import map, plant, zombie, menubar


class Level(tool.State):  # 定义一个名为 Level 的类，继承自 tool.State 类
    def __init__(self):  # 初始化方法
        tool.State.__init__(self)  # 调用父类的初始化方法

    def startup(self, current_time, persist):  # 定义了一个名为 startup 的方法，用于开始关卡
        self.game_info = persist  # 将参数 persist 赋值给实例变量 game_info
        self.persist = self.game_info  # 将 game_info 赋值给实例变量 persist
        self.game_info[c.CURRENT_TIME] = current_time  # 将参数 current_time 存储到 game_info 中
        self.map_y_len = c.GRID_Y_LEN  # 设置地图的纵向格子数量为常量 GRID_Y_LEN
        self.map = map.Map(c.GRID_X_LEN, self.map_y_len)  # 创建地图对象

        self.loadMap()# 载入地图数据
        self.setupBackground()# 设置背景
        self.initState()# 初始化游戏状态

    def loadMap(self): # 载入地图数据的方法
        map_file = 'level_' + str(self.game_info[c.LEVEL_NUM]) + '.json' # 根据当前关卡号生成地图文件名
        file_path = os.path.join('source', 'data', 'map', map_file) # 拼接文件路径
        f = open(file_path) # 打开地图文件
        self.map_data = json.load(f) # 读取地图数据
        f.close()
    
    def setupBackground(self): # 设置背景的方法
        img_index = self.map_data[c.BACKGROUND_TYPE] # 获取地图数据中的背景类型索引
        self.background_type = img_index # 将背景类型索引存储到实例变量中
        self.background = tool.GFX[c.BACKGROUND_NAME][img_index]# 获取背景图像
        self.bg_rect = self.background.get_rect() # 获取背景矩形区域

        self.level = pg.Surface((self.bg_rect.w, self.bg_rect.h)).convert()  # 创建与背景相同大小的表面
        self.viewport = tool.SCREEN.get_rect(bottom=self.bg_rect.bottom)  # 设置视口位置
        self.viewport.x += c.BACKGROUND_OFFSET_X  # 调整视口 x 坐标

    def setupGroups(self):  # 设置游戏中的精灵组
        self.sun_group = pg.sprite.Group()  # 创建阳光精灵组
        self.head_group = pg.sprite.Group()  # 创建头部精灵组

        # 存储实体精灵组的列表
        self.plant_groups = []
        self.zombie_groups = []
        self.hypno_zombie_groups = [] #zombies who are hypno after eating hypnoshroom
        self.bullet_groups = []
        for i in range(self.map_y_len):
            self.plant_groups.append(pg.sprite.Group())
            self.zombie_groups.append(pg.sprite.Group())
            self.hypno_zombie_groups.append(pg.sprite.Group())
            self.bullet_groups.append(pg.sprite.Group())
    
    def setupZombies(self):# 初始化僵尸
        def takeTime(element):# 定义一个用于排序的函数，按时间排序
            return element[0]

        self.zombie_list = []# 存储僵尸的列表
        for data in self.map_data[c.ZOMBIE_LIST]: # 遍历地图数据中的僵尸列表
            self.zombie_list.append((data['time'], data['name'], data['map_y']))  # 将僵尸数据添加到列表中
            self.zombie_start_time = 0  # 初始化僵尸开始时间
            self.zombie_list.sort(key=takeTime)  # 对僵尸列表按时间排序

    def setupCars(self):  # 初始化车辆
        self.cars = []  # 存储车辆的列表
        for i in range(self.map_y_len):  # 根据地图的纵向格子数量循环
            _, y = self.map.getMapGridPos(0, i)  # 获取车辆的初始位置
            self.cars.append(plant.Car(-25, y + 20, i))  # 创建并添加车辆对象到列表中

    def update(self, surface, current_time, mouse_pos, mouse_click):  # 更新游戏状态
        self.current_time = self.game_info[c.CURRENT_TIME] = current_time  # 更新当前时间
        if self.state == c.CHOOSE:  # 如果游戏状态为选择状态
            self.choose(mouse_pos, mouse_click)  # 调用选择方法
        elif self.state == c.PLAY:  # 如果游戏状态为游戏状态
            self.play(mouse_pos, mouse_click)  # 调用游戏方法

        self.draw(surface)  # 绘制游戏界面

    def initBowlingMap(self):  # 初始化保龄球地图
        print('initBowlingMap')  # 打印初始化信息
        for x in range(3, self.map.width):  # 循环遍历地图宽度（保留 3 列）
            for y in range(self.map.height):  # 循环遍历地图高度
                self.map.setMapGridType(x, y, c.MAP_EXIST)  # 设置地图格子类型为存在

    def initState(self):#初始化游戏状态
        if c.CHOOSEBAR_TYPE in self.map_data:#检查地图数据中是否包含选择栏类型
            self.bar_type = self.map_data[c.CHOOSEBAR_TYPE]
        else:
            self.bar_type = c.CHOOSEBAR_STATIC

        if self.bar_type == c.CHOOSEBAR_STATIC:#根据选择栏的类型进行不同的初始化操作。
            self.initChoose()
        else:
            card_pool = menubar.getCardPool(self.map_data[c.CARD_POOL])
            self.initPlay(card_pool)
            if self.bar_type == c.CHOSSEBAR_BOWLING:
                self.initBowlingMap()

    def initChoose(self):#初始化选择状态，并创建一个面板对象。
        self.state = c.CHOOSE
        self.panel = menubar.Panel(menubar.all_card_list, self.map_data[c.INIT_SUN_NAME])

    def choose(self, mouse_pos, mouse_click):#处理用户的选择操作
        if mouse_pos and mouse_click[0]:
            self.panel.checkCardClick(mouse_pos)
            if self.panel.checkStartButtonClick(mouse_pos):
                self.initPlay(self.panel.getSelectedCards())

    def initPlay(self, card_list):  # 定义初始化游戏状态方法，接收一个卡片列表作为参数
        self.state = c.PLAY  # 设置游戏状态为游戏中

        # 根据选择栏类型初始化菜单栏
        if self.bar_type == c.CHOOSEBAR_STATIC:
            self.menubar = menubar.MenuBar(card_list, self.map_data[c.INIT_SUN_NAME])
        else:
            self.menubar = menubar.MoveBar(card_list)

        self.drag_plant = False  # 初始化拖拽植物状态为False
        self.hint_image = None  # 初始化提示图片为None
        self.hint_plant = False  # 初始化提示植物状态为False

        # 如果背景类型为白天且选择栏类型为静态
        if self.background_type == c.BACKGROUND_DAY and self.bar_type == c.CHOOSEBAR_STATIC:
            self.produce_sun = True  # 设置生成阳光为True
        else:
            self.produce_sun = False  # 否则设置生成阳光为False

        self.sun_timer = self.current_time  # 设置阳光生成定时器为当前时间

        self.removeMouseImage()  # 移除鼠标图片
        self.setupGroups()  # 设置游戏中的组
        self.setupZombies()  # 设置僵尸
        self.setupCars()  # 设置车辆

    def play(self, mouse_pos, mouse_click):
        if self.zombie_start_time == 0:  # 如果僵尸开始时间为0
            self.zombie_start_time = self.current_time  # 则将僵尸开始时间设置为当前时间
        elif len(self.zombie_list) > 0:  # 否则如果僵尸列表不为空
            data = self.zombie_list[0]  # 获取僵尸列表中的第一个元素
            if data[0] <= (self.current_time - self.zombie_start_time):  # 如果第一个元素的时间已经到达
                self.createZombie(data[1], data[2])  # 创建对应的僵尸
                self.zombie_list.remove(data)  # 从僵尸列表中移除该元素

        # 更新子弹、植物、僵尸、被催眠的僵尸的位置和状态
        for i in range(self.map_y_len):
            self.bullet_groups[i].update(self.game_info)
            self.plant_groups[i].update(self.game_info)
            self.zombie_groups[i].update(self.game_info)
            self.hypno_zombie_groups[i].update(self.game_info)
            for zombie in self.hypno_zombie_groups[i]:
                if zombie.rect.x > c.SCREEN_WIDTH:
                    zombie.kill()  # 如果被催眠的僵尸超出屏幕范围，则移除

        self.head_group.update(self.game_info)  # 更新头部组
        self.sun_group.update(self.game_info)  # 更新阳光组

        if not self.drag_plant and mouse_pos and mouse_click[0]:  # 如果不是拖拽植物且鼠标位置和左键被点击
            result = self.menubar.checkCardClick(mouse_pos)  # 检查菜单栏中的卡片点击
            if result:  # 如果有结果
                self.setupMouseImage(result[0], result[1])  # 设置鼠标图片为对应植物的图片
        elif self.drag_plant:  # 如果是拖拽植物
            if mouse_click[1]:  # 如果右键被点击
                self.removeMouseImage()  # 移除鼠标图片
            elif mouse_click[0]:  # 如果左键被点击
                if self.menubar.checkMenuBarClick(mouse_pos):  # 检查菜单栏是否被点击
                    self.removeMouseImage()  # 移除鼠标图片
                else:
                    self.addPlant()  # 否则添加植物到游戏中
            elif mouse_pos is None:  # 如果鼠标位置为空
                self.setupHintImage()  # 设置提示图片

        if self.produce_sun:  # 如果需要生成阳光
            if (self.current_time - self.sun_timer) > c.PRODUCE_SUN_INTERVAL:  # 如果距离上次生成阳光的时间超过了设定的时间间隔
                self.sun_timer = self.current_time  # 更新阳光计时器为当前时间
                map_x, map_y = self.map.getRandomMapIndex()  # 获取随机地图索引
                x, y = self.map.getMapGridPos(map_x, map_y)  # 获取对应地图格子的位置
                self.sun_group.add(plant.Sun(x, 0, x, y))  # 在指定位置生成阳光并添加到阳光组中

        if not self.drag_plant and mouse_pos and mouse_click[0]:  # 如果不是拖拽植物且鼠标位置和左键被点击
            for sun in self.sun_group:  # 遍历阳光组中的每个阳光对象
                if sun.checkCollision(mouse_pos[0], mouse_pos[1]):  # 如果鼠标位置与某个阳光对象发生碰撞
                    self.menubar.increaseSunValue(sun.sun_value)  # 增加阳光价值到菜单栏

        for car in self.cars:  # 遍历车辆列表中的每辆车
            car.update(self.game_info)  # 更新车辆状态

        self.menubar.update(self.current_time)  # 更新菜单栏状态

        self.checkBulletCollisions()  # 检查子弹碰撞
        self.checkZombieCollisions()  # 检查僵尸碰撞
        self.checkPlants()  # 检查植物状态
        self.checkCarCollisions()  # 检查车辆碰撞
        self.checkGameState()  # 检查游戏状态

    def createZombie(self, name, map_y):
        x, y = self.map.getMapGridPos(0, map_y)  # 获取僵尸出现的初始位置
        if name == c.NORMAL_ZOMBIE:  # 如果是普通僵尸
            self.zombie_groups[map_y].add(
                zombie.NormalZombie(c.ZOMBIE_START_X, y, self.head_group))  # 在指定位置添加普通僵尸对象到对应的僵尸组中
        elif name == c.CONEHEAD_ZOMBIE:  # 如果是锥桶僵尸
            self.zombie_groups[map_y].add(
                zombie.ConeHeadZombie(c.ZOMBIE_START_X, y, self.head_group))  # 在指定位置添加锥桶僵尸对象到对应的僵尸组中
        elif name == c.BUCKETHEAD_ZOMBIE:  # 如果是铁桶僵尸
            self.zombie_groups[map_y].add(
                zombie.BucketHeadZombie(c.ZOMBIE_START_X, y, self.head_group))  # 在指定位置添加铁桶僵尸对象到对应的僵尸组中
        elif name == c.FLAG_ZOMBIE:  # 如果是旗帜僵尸
            self.zombie_groups[map_y].add(
                zombie.FlagZombie(c.ZOMBIE_START_X, y, self.head_group))  # 在指定位置添加旗帜僵尸对象到对应的僵尸组中
        elif name == c.NEWSPAPER_ZOMBIE:  # 如果是报纸僵尸
            self.zombie_groups[map_y].add(
                zombie.NewspaperZombie(c.ZOMBIE_START_X, y, self.head_group))  # 在指定位置添加报纸僵尸对象到对应的僵尸组中

    def canSeedPlant(self):
        x, y = pg.mouse.get_pos()  # 获取鼠标当前位置
        return self.map.showPlant(x, y)  # 在地图上显示植物可种植的位置并返回结果

    def addPlant(self):# 检查是否可以在当前位置种植植物
        pos = self.canSeedPlant()
        if pos is None:
            return
        # 如果提示图片为空，则设置提示图片
        if self.hint_image is None:
            self.setupHintImage()
        x, y = self.hint_rect.centerx, self.hint_rect.bottom
        # 根据提示图片的坐标计算在地图上的位置
        map_x, map_y = self.map.getMapIndex(x, y)

        # 根据当前选中的植物种类创建对应的植物对象
        if self.plant_name == c.SUNFLOWER:
            new_plant = plant.SunFlower(x, y, self.sun_group)
        elif self.plant_name == c.PEASHOOTER:
            new_plant = plant.PeaShooter(x, y, self.bullet_groups[map_y])
        elif self.plant_name == c.SNOWPEASHOOTER:
            new_plant = plant.SnowPeaShooter(x, y, self.bullet_groups[map_y])
            # 其他植物的创建过程类似，根据不同的植物名称选择对应的类来创建对象

            # 如果新植物可以休眠且当前为白天背景，则设置休眠状态
        if new_plant.can_sleep and self.background_type == c.BACKGROUND_DAY:
            new_plant.setSleep()
            # 将新植物添加到对应的植物组中
        self.plant_groups[map_y].add(new_plant)

        # 根据工具栏类型执行不同的操作
        if self.bar_type == c.CHOOSEBAR_STATIC:
            # 如果是静态选择工具栏，则减少阳光值，并设置卡片冷冻时间
            self.menubar.decreaseSunValue(self.select_plant.sun_cost)
            self.menubar.setCardFrozenTime(self.plant_name)
        else:
            # 否则，删除对应的卡片
            self.menubar.deleateCard(self.select_plant)

        # 如果工具栏类型不是保龄球工具栏，则将地图上对应位置设置为已占用状态
        if self.bar_type != c.CHOSSEBAR_BOWLING:
            self.map.setMapGridType(map_x, map_y, c.MAP_EXIST)

        # 移除鼠标图片
        self.removeMouseImage()
        # 打印调试信息，注释掉了
        #print('addPlant map[%d,%d], grid pos[%d, %d] pos[%d, %d]' % (map_x, map_y, x, y, pos[0], pos[1]))

    def setupHintImage(self):
        # 检查是否可以在当前位置种植植物
        pos = self.canSeedPlant()
        # 如果有可用位置并且有鼠标图片
        if pos and self.mouse_image:
            # 如果已经存在提示图片，并且提示图片位置与新位置相同，则直接返回
            if (self.hint_image and pos[0] == self.hint_rect.x and
                    pos[1] == self.hint_rect.y):
                return
            # 创建新的表面用于显示提示图片
            width, height = self.mouse_rect.w, self.mouse_rect.h
            image = pg.Surface([width, height])
            # 将鼠标图片绘制到提示图片表面上
            image.blit(self.mouse_image, (0, 0), (0, 0, width, height))
            # 设置颜色键以便透明显示
            image.set_colorkey(c.BLACK)
            # 设置图片透明度
            image.set_alpha(128)
            # 更新提示图片和位置
            self.hint_image = image
            self.hint_rect = image.get_rect()
            self.hint_rect.centerx = pos[0]
            self.hint_rect.bottom = pos[1]
            self.hint_plant = True
        else:
            self.hint_plant = False

    def setupMouseImage(self, plant_name, select_plant):
        # 获取植物的帧列表
        frame_list = tool.GFX[plant_name]
        # 如果植物在工具栏中有预设的矩形范围，则获取该范围
        if plant_name in tool.PLANT_RECT:
            data = tool.PLANT_RECT[plant_name]
            x, y, width, height = data['x'], data['y'], data['width'], data['height']
        else:
            # 否则，使用第一帧的大小
            x, y = 0, 0
            rect = frame_list[0].get_rect()
            width, height = rect.w, rect.h

        # 如果植物是以下类型之一，则将鼠标图片的颜色设置为白色，否则设置为黑色
        if (plant_name == c.POTATOMINE or plant_name == c.SQUASH or
                plant_name == c.SPIKEWEED or plant_name == c.JALAPENO or
                plant_name == c.SCAREDYSHROOM or plant_name == c.SUNSHROOM or
                plant_name == c.ICESHROOM or plant_name == c.HYPNOSHROOM or
                plant_name == c.WALLNUTBOWLING or plant_name == c.REDWALLNUTBOWLING):
            color = c.WHITE
        else:
            color = c.BLACK
        # 获取植物的鼠标图片
        self.mouse_image = tool.get_image(frame_list[0], x, y, width, height, color, 1)
        self.mouse_rect = self.mouse_image.get_rect()
        # 隐藏系统鼠标
        pg.mouse.set_visible(False)
        # 设置拖拽植物标志为真，并记录当前选中的植物名称和对象
        self.drag_plant = True
        self.plant_name = plant_name
        self.select_plant = select_plant

    def removeMouseImage(self):
        # 恢复系统鼠标可见
        pg.mouse.set_visible(True)
        # 将拖拽植物标志设为假，并清空鼠标图片和提示图片
        self.drag_plant = False
        self.mouse_image = None
        self.hint_image = None
        self.hint_plant = False

    def checkBulletCollisions(self):
        # 使用圆形碰撞检测函数，设定碰撞比率为0.7
        collided_func = pg.sprite.collide_circle_ratio(0.7)
        # 遍历每一行的子弹组
        for i in range(self.map_y_len):
            for bullet in self.bullet_groups[i]:
                # 如果子弹处于飞行状态
                if bullet.state == c.FLY:
                    # 检查子弹与僵尸组中的任何僵尸是否发生碰撞
                    zombie = pg.sprite.spritecollideany(bullet, self.zombie_groups[i], collided_func)
                    # 如果有碰撞并且僵尸不处于死亡状态
                    if zombie and zombie.state != c.DIE:
                        # 设置僵尸受到子弹伤害，并根据子弹是否为冰属性进行相应处理
                        zombie.setDamage(bullet.damage, bullet.ice)
                        # 设置子弹为爆炸状态
                        bullet.setExplode()

    def checkZombieCollisions(self):
        # 检查僵尸和其他游戏元素的碰撞
        if self.bar_type == c.CHOSSEBAR_BOWLING:
            ratio = 0.6
        else:
            ratio = 0.7
        collided_func = pg.sprite.collide_circle_ratio(ratio)
        for i in range(self.map_y_len):
            hypo_zombies = []
            for zombie in self.zombie_groups[i]:
                if zombie.state != c.WALK:
                    continue
                # 检测僵尸和植物的碰撞
                plant = pg.sprite.spritecollideany(zombie, self.plant_groups[i], collided_func)
                if plant:
                    if plant.name == c.WALLNUTBOWLING:
                        if plant.canHit(i):
                            zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE)
                            plant.changeDirection(i)
                    elif plant.name == c.REDWALLNUTBOWLING:
                        if plant.state == c.IDLE:
                            plant.setAttack()
                    elif plant.name != c.SPIKEWEED:
                        zombie.setAttack(plant)

            for hypno_zombie in self.hypno_zombie_groups[i]:
                if hypno_zombie.health <= 0:
                    continue
                # 检测催眠僵尸和其他僵尸的碰撞
                zombie_list = pg.sprite.spritecollide(hypno_zombie, self.zombie_groups[i], False, collided_func)
                for zombie in zombie_list:
                    if zombie.state == c.DIE:
                        continue
                    if zombie.state == c.WALK:
                        zombie.setAttack(hypno_zombie, False)
                    if hypno_zombie.state == c.WALK:
                        hypno_zombie.setAttack(zombie, False)

    def checkCarCollisions(self):
        # 检测车辆和僵尸的碰撞
        collided_func = pg.sprite.collide_circle_ratio(0.8)
        for car in self.cars:
            zombies = pg.sprite.spritecollide(car, self.zombie_groups[car.map_y], False, collided_func)
            for zombie in zombies:
                if zombie and zombie.state != c.DIE:
                    car.setWalk()
                    zombie.setDie()
            if car.dead:
                self.cars.remove(car)

    def boomZombies(self, x, map_y, y_range, x_range):
        # 爆炸效果，影响范围内的僵尸
        for i in range(self.map_y_len):
            if abs(i - map_y) > y_range:
                continue
            for zombie in self.zombie_groups[i]:
                if abs(zombie.rect.centerx - x) <= x_range:
                    zombie.setBoomDie()

    def freezeZombies(self, plant):
        # 冰冻效果，冻结附近的僵尸
        for i in range(self.map_y_len):
            for zombie in self.zombie_groups[i]:
                if zombie.rect.centerx < c.SCREEN_WIDTH:
                    zombie.setFreeze(plant.trap_frames[0])

    def killPlant(self, plant):
        # 移除植物，并触发相应效果
        x, y = plant.getPosition()
        map_x, map_y = self.map.getMapIndex(x, y)
        if self.bar_type != c.CHOSSEBAR_BOWLING:
            self.map.setMapGridType(map_x, map_y, c.MAP_EMPTY)
        if (plant.name == c.CHERRYBOMB or plant.name == c.JALAPENO or
                (plant.name == c.POTATOMINE and not plant.is_init) or
                plant.name == c.REDWALLNUTBOWLING):
            self.boomZombies(plant.rect.centerx, map_y, plant.explode_y_range, plant.explode_x_range)
        elif plant.name == c.ICESHROOM and plant.state != c.SLEEP:
            self.freezeZombies(plant)
        elif plant.name == c.HYPNOSHROOM and plant.state != c.SLEEP:
            zombie = plant.kill_zombie
            zombie.setHypno()
            _, map_y = self.map.getMapIndex(zombie.rect.centerx, zombie.rect.bottom)
            self.zombie_groups[map_y].remove(zombie)
            self.hypno_zombie_groups[map_y].add(zombie)
        plant.kill()

    def checkPlant(self, plant, i):
        # 获取当前行的僵尸数量
        zombie_len = len(self.zombie_groups[i])

        # 对于三个豌豆射手的情况
        if plant.name == c.THREEPEASHOOTER:
            if plant.state == c.IDLE:
                # 如果当前行有僵尸，设置豌豆射手为攻击状态
                if zombie_len > 0:
                    plant.setAttack()
                # 如果前一行有僵尸，设置豌豆射手为攻击状态
                elif (i - 1) >= 0 and len(self.zombie_groups[i - 1]) > 0:
                    plant.setAttack()
                # 如果后一行有僵尸，设置豌豆射手为攻击状态
                elif (i + 1) < self.map_y_len and len(self.zombie_groups[i + 1]) > 0:
                    plant.setAttack()
            elif plant.state == c.ATTACK:
                # 如果当前行有僵尸，继续攻击
                if zombie_len > 0:
                    pass
                # 如果前一行有僵尸，继续攻击
                elif (i - 1) >= 0 and len(self.zombie_groups[i - 1]) > 0:
                    pass
                # 如果后一行有僵尸，继续攻击
                elif (i + 1) < self.map_y_len and len(self.zombie_groups[i + 1]) > 0:
                    pass
                # 否则，设置为待机状态
                else:
                    plant.setIdle()

        # 对于食人花的情况
        elif plant.name == c.CHOMPER:
            for zombie in self.zombie_groups[i]:
                # 如果食人花可以攻击到僵尸，设置为攻击状态并跳出循环
                if plant.canAttack(zombie):
                    plant.setAttack(zombie, self.zombie_groups[i])
                    break

        # 对于土豆雷的情况
        elif plant.name == c.POTATOMINE:
            for zombie in self.zombie_groups[i]:
                # 如果土豆雷可以攻击到僵尸，设置为攻击状态并跳出循环
                if plant.canAttack(zombie):
                    plant.setAttack()
                    break

        # 对于南瓜投手的情况
        elif plant.name == c.SQUASH:
            for zombie in self.zombie_groups[i]:
                # 如果南瓜投手可以攻击到僵尸，设置为攻击状态并跳出循环
                if plant.canAttack(zombie):
                    plant.setAttack(zombie, self.zombie_groups[i])
                    break

        # 对于地刺的情况
        elif plant.name == c.SPIKEWEED:
            can_attack = False
            for zombie in self.zombie_groups[i]:
                # 如果地刺可以攻击到僵尸，设置为攻击状态并跳出循环
                if plant.canAttack(zombie):
                    can_attack = True
                    break
            if plant.state == c.IDLE and can_attack:
                plant.setAttack(self.zombie_groups[i])
            elif plant.state == c.ATTACK and not can_attack:
                plant.setIdle()

        # 对于胆小菇的情况
        elif plant.name == c.SCAREDYSHROOM:
            need_cry = False
            can_attack = False
            for zombie in self.zombie_groups[i]:
                # 如果胆小菇需要哭泣，设置为哭泣状态并跳出循环
                if plant.needCry(zombie):
                    need_cry = True
                    break
                # 如果胆小菇可以攻击到僵尸，设置为攻击状态
                elif plant.canAttack(zombie):
                    can_attack = True
            if need_cry:
                if plant.state != c.CRY:
                    plant.setCry()
            elif can_attack:
                if plant.state != c.ATTACK:
                    plant.setAttack()
            elif plant.state != c.IDLE:
                plant.setIdle()

        # 对于坚果投手的情况
        elif (plant.name == c.WALLNUTBOWLING or
              plant.name == c.REDWALLNUTBOWLING):
            pass

        else:
            can_attack = False
            if (plant.state == c.IDLE and zombie_len > 0):
                for zombie in self.zombie_groups[i]:
                    # 如果植物可以攻击到僵尸，设置为攻击状态并跳出循环
                    if plant.canAttack(zombie):
                        can_attack = True
                        break
            if plant.state == c.IDLE and can_attack:
                plant.setAttack()
            elif (plant.state == c.ATTACK and not can_attack):
                plant.setIdle()

    def checkPlants(self):
        # 遍历每一行
        for i in range(self.map_y_len):
            # 遍历当前行的所有植物
            for plant in self.plant_groups[i]:
                # 如果植物不处于睡眠状态，对其进行检查
                if plant.state != c.SLEEP:
                    self.checkPlant(plant, i)
                # 如果植物的生命值小于等于0，移除该植物
                if plant.health <= 0:
                    self.killPlant(plant)

    def checkVictory(self):
        # 检查是否还有僵尸存活
        if len(self.zombie_list) > 0:
            return False
        # 检查每一行是否还有僵尸存活
        for i in range(self.map_y_len):
            if len(self.zombie_groups[i]) > 0:
                return False
        # 如果没有僵尸存活，返回胜利状态
        return True

    def checkLose(self):
        # 检查每一行的僵尸是否超出屏幕左边界，表示玩家失败
        for i in range(self.map_y_len):
            for zombie in self.zombie_groups[i]:
                if zombie.rect.right < 0:
                    return True
        return False

    def checkGameState(self):
        # 检查游戏状态，如果胜利，则进入下一关；如果失败，则进入失败状态
        if self.checkVictory():
            self.game_info[c.LEVEL_NUM] += 1
            self.next = c.GAME_VICTORY
            self.done = True
        elif self.checkLose():
            self.next = c.GAME_LOSE
            self.done = True

    def drawMouseShow(self, surface):
        # 绘制鼠标提示
        if self.hint_plant:
            surface.blit(self.hint_image, self.hint_rect)
        x, y = pg.mouse.get_pos()
        self.mouse_rect.centerx = x
        self.mouse_rect.centery = y
        surface.blit(self.mouse_image, self.mouse_rect)

    def drawZombieFreezeTrap(self, i, surface):
        # 绘制僵尸的冰冻陷阱效果
        for zombie in self.zombie_groups[i]:
            zombie.drawFreezeTrap(surface)

    def draw(self, surface):
        # 绘制游戏界面
        self.level.blit(self.background, self.viewport, self.viewport)
        surface.blit(self.level, (0, 0), self.viewport)
        if self.state == c.CHOOSE:
            # 绘制植物选择界面
            self.panel.draw(surface)
        elif self.state == c.PLAY:
            # 绘制游戏进行中的界面
            self.menubar.draw(surface)
            for i in range(self.map_y_len):
                # 绘制每一行的植物、僵尸、催眠僵尸、子弹等
                self.plant_groups[i].draw(surface)
                self.zombie_groups[i].draw(surface)
                self.hypno_zombie_groups[i].draw(surface)
                self.bullet_groups[i].draw(surface)
                self.drawZombieFreezeTrap(i, surface)
            for car in self.cars:
                # 绘制汽车
                car.draw(surface)
            self.head_group.draw(surface)
            self.sun_group.draw(surface)

            if self.drag_plant:
                # 绘制拖拽的植物
                self.drawMouseShow(surface)
